package com.huawei.java.main.algorithm;

import com.huawei.java.main.classes.Request;
import com.huawei.java.main.classes.Server;
import com.huawei.java.main.classes.Service;

import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Arrange {
    public static Map<String, Service> getServiceMap(List<Service> services) {
        Map<String, Service> serviceMap = new HashMap<>();
        for (Service service : services) {
            serviceMap.put(service.getType(), service);
        }
        return serviceMap;
    }

    public static int[] getMaxRequirement(List<Request> requests, Map<String, Service> serviceMap) {
        Map<Integer, Service> aliveVm = new HashMap<>();
        Usage singleMemory = new Usage();
        Usage singleCPU = new Usage();
        Usage doubleMemory = new Usage();
        Usage doubleCPU = new Usage();

        for (Request request : requests) {
            if (request.isAdd()) {
                final String vmType = request.getServiceType();
                final Service newVm = serviceMap.get(vmType);
                aliveVm.put(request.getServiceId(), newVm);

                if (newVm.isDoubleDeploy()) {
                    doubleMemory.add(newVm.getMemory());
                    doubleCPU.add(newVm.getCpu());
                } else {
                    singleMemory.add(newVm.getMemory());
                    singleCPU.add(newVm.getCpu());
                }
            } else {
                final int vmID = request.getServiceId();
                final Service delVm = aliveVm.get(vmID);
                aliveVm.remove(vmID);

                if (delVm.isDoubleDeploy()) {
                    doubleMemory.del(delVm.getMemory());
                    doubleCPU.del(delVm.getCpu());
                } else {
                    singleMemory.del(delVm.getMemory());
                    singleCPU.del(delVm.getCpu());
                }
            }
        }

        return new int[]{singleMemory.getMax(), singleCPU.getMax(), doubleMemory.getMax(), doubleCPU.getMax()};
    }

    public static double averageResourceRatio(List<Service> services) {
        return services.stream()
                .mapToDouble(service -> (double) service.getCpu() / (double) service.getMemory())
                .average()
                .orElseThrow(UnknownError::new);
    }

    public static List<Server> sortByCpuCostEffective(List<Server> servers, int day) {
        return servers.stream()
                .sorted(Comparator.comparingDouble(
                        server -> (double) server.getCpu() / ((double) server.getPrice() / day + server.getCost())
                ))
                .collect(Collectors.toList());
    }

    public static List<Server> sortByMemoryCostEffective(List<Server> servers, int day) {
        return servers.stream()
                .sorted(Comparator.comparingDouble(
                        server -> (double) server.getMemory() / ((double) server.getPrice() / day + server.getCost())
                ))
                .collect(Collectors.toList());
    }
}
